home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Users Group Library 1996 July
/
C-C++ Users Group Library July 1996.iso
/
listings
/
v_11_02
/
1102042a
< prev
next >
Wrap
Text File
|
1992-12-05
|
4KB
|
135 lines
/******************************************************
*
* fp2ratio.c
*
* Floating-point number to ratio approximation.
*
* Usage: fp2ratio number
*
* Compiler: Microsoft C 6.0 using inline
* floating-point emulator (option /FPi).
*
*****************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
/* Maximum argument significant digits. */
#define MAX_SIG_DIGITS 9
#define ARRAY_SIZE 2
#define I ( i ) % ARRAY_SIZE
#define I_MINUS_1 ( i - 1 ) % ARRAY_SIZE
#define I_MINUS_2 ( i ) % ARRAY_SIZE
typedef unsigned long Ulong;
typedef long double Ldouble;
int main( int argc, char **argv )
{
int i, dec_digits, sign;
Ulong n0, n, d0, d, temp;
Ulong p[ARRAY_SIZE] = { 0, 1 };
Ulong q[ARRAY_SIZE] = { 1, 0 };
double x;
Ldouble percent_err;
/* Check for one command-line argument. */
if ( argc != 2 )
{
fprintf(stderr, "Usage: %s number\n", argv[0]);
exit( EXIT_FAILURE );
}
else /* argc == 2 */
x = strtod( argv[1], (char **) NULL );
/* Handle zero and negative arguments. */
if ( x < 0.0 )
{
sign = -1;
x = -x;
}
else if ( x == 0.0 )
{
puts( "\n0:\n" );
puts( " 0 / 1 Exactly!" );
exit( EXIT_SUCCESS );
}
else /* x > 0.0 */
sign = 1;
/* Check for out-of-range arguments. */
if ( x >= pow( 10.0, (double) MAX_SIG_DIGITS ) )
{
fprintf( stderr, "%s: Magnitude is", argv[1] );
fprintf( stderr, " too large.\n" );
exit( EXIT_FAILURE );
}
else if ( x <=
pow( 10.0, (double) -MAX_SIG_DIGITS) / 2.0 )
{
fprintf( stderr, "%s: Magnitude is", argv[1] );
fprintf( stderr, " too small.\n" );
exit( EXIT_FAILURE );
}
/* Determine the argument's radix-10 ratio. */
d0 = (Ulong) pow( 10.0, (double) MAX_SIG_DIGITS -
((x < 1.0) ? 0.0 : floor( 1.0 + log10( x ))));
n0 = (Ulong) ( ( x * (double) d0 ) + 0.5 );
printf( "\n%.*g:\n\n", MAX_SIG_DIGITS,
(double) n0 / (double) d0 );
/* Iteratively determine integer ratios. */
for ( i = 2, d = d0, n = n0 ; ;
i++, temp = d, d = n % d, n = temp )
{
p[I] = n / d * p[I_MINUS_1] + p[I_MINUS_2];
q[I] = n / d * q[I_MINUS_1] + q[I_MINUS_2];
/* Print ratios with non-zero numerators. */
if ( p[I] != 0 )
{
printf("%11ld / %-10lu", sign * p[I], q[I]);
if ( n % d == 0 )
{
printf( " Exactly!\n" );
break;
}
/*
* Compute the ratio's percent error
* (taking care to avoid significance
* loss when subtracting nearly equal
* values):
*
* percent error =
*
*
* 100 * ( p[i] * d0 - q[i] * n0 )
* -------------------------------------
* q[I] * n0
*
* Display in %f format with at least two
* significant digits.
*/
percent_err = (Ldouble) p[I] * (Ldouble) d0;
percent_err -= (Ldouble) q[I] * (Ldouble) n0;
percent_err *= 100.0L;
percent_err /= (Ldouble) q[I] * (Ldouble) n0;
dec_digits =
( fabs( (double) percent_err ) >= 10.0 ) ?
1 : 1 + ( int ) ( fabs( floor(
log10( fabs( (double) percent_err )))));
printf( "%+*.*Lf%%\n", dec_digits + 6,
dec_digits, percent_err );
}
}
exit( EXIT_SUCCESS );
}